/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
 *
 * @file    mapi_vcap_hal_serdes.c
 * @brief   server vcap serdes module
 * @author  HiMobileCam NDK develop team
 * @date  2019-3-26
 */
#include <string.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "hi_mapi_comm_define.h"
#include "mapi_vcap_inner.h"
#include "hi_mapi_vcap_define.h"
#include "mapi_comm_inner.h"
#include "mpi_sys.h"
#include "sensor_comm.h"
#include "hi_mapi_hal_serdes_define.h"
#include "sensor_interface_cfg_params.h"
#ifdef SUPPORT_SERDES
#include "hi_serdes.h"
#endif

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */

#ifdef SUPPORT_SERDES
static MAPI_HAL_SERDES_DEV_S g_stSerdesDev[HI_MAPI_VCAP_SERDES_MAX_NUM];
static HI_S32 g_as32SerdesSnsType[HI_MAPI_VCAP_MAX_DEV_NUM];

HI_S32 MAPI_VCAP_ResetSerdesDev(HI_HANDLE SerdesHdl)
{
    HI_S32 s32Ret;
    HI_S32 i;

    s32Ret = memset_s(&g_stSerdesDev[SerdesHdl], sizeof(MAPI_HAL_SERDES_DEV_S), 0x00, sizeof(MAPI_HAL_SERDES_DEV_S));
    MAPI_CHECK_RET(HI_MAPI_MOD_VCAP, "memset_s", s32Ret);

    for (i = 0; i < HI_MAPI_VCAP_SERDES_BINDDEV_MAX_NUM; i++) {
        g_stSerdesDev[SerdesHdl].BindDevHdl[i] = HI_INVALID_HANDLE;
    }

    return HI_SUCCESS;
}

HI_S32 MAPI_VCAP_SetSerdesSnsType(const HI_S32 *pSensorType)
{
    HI_S32 s32Ret;

    CHECK_MAPI_VCAP_NULL_PTR_RET(pSensorType);

    s32Ret = memcpy_s(g_as32SerdesSnsType, sizeof(HI_S32) * HI_MAPI_VCAP_MAX_DEV_NUM, pSensorType,
        sizeof(HI_S32) * HI_MAPI_VCAP_MAX_DEV_NUM);
    MAPI_CHECK_RET(HI_MAPI_MOD_VCAP, "memcpy_s", s32Ret);

    return HI_SUCCESS;
}

HI_HANDLE MAPI_VCAP_GetBindSerdesHdl(HI_HANDLE VcapDevHdl)
{
    HI_S32 i;
    HI_S32 j;

    for (i = 0; i < HI_MAPI_VCAP_SERDES_MAX_NUM; i++) {
        for (j = 0; j < HI_MAPI_VCAP_SERDES_BINDDEV_MAX_NUM; j++) {
            if (g_stSerdesDev[i].BindDevHdl[j] == VcapDevHdl) {
                return i;
            }
        }
    }

    return HI_INVALID_HANDLE;
}

HI_BOOL MAPI_VCAP_IsMultiSerdes(HI_HANDLE VcapDevHdl)
{
    HI_S32 i;
    HI_S32 j;

    for (i = 0; i < HI_MAPI_VCAP_SERDES_MAX_NUM; i++) {
        for (j = 0; j < HI_MAPI_VCAP_SERDES_BINDDEV_MAX_NUM; j++) {
            if (g_stSerdesDev[i].BindDevHdl[j] == VcapDevHdl && g_stSerdesDev[i].bEnable) {
                return g_stSerdesDev[i].multiInput;
            }
        }
    }

    return HI_FALSE;
}


HI_S32 MAPI_VCAP_GetBindDevHdls(HI_HANDLE SerdesHdl, HI_HANDLE *pBindDevHdl, HI_U32 *pu32BindNum)
{
    HI_S32 s32Ret;

    s32Ret = memcpy_s(pBindDevHdl, sizeof(HI_HANDLE) * HI_MAPI_VCAP_SERDES_BINDDEV_MAX_NUM,
        g_stSerdesDev[SerdesHdl].BindDevHdl, sizeof(HI_HANDLE) * HI_MAPI_VCAP_SERDES_BINDDEV_MAX_NUM);
    MAPI_CHECK_RET(HI_MAPI_MOD_VCAP, "memcpy_s", s32Ret);

    *pu32BindNum = g_stSerdesDev[SerdesHdl].u32BindNum;

    return HI_SUCCESS;
}


static HI_U32 MAPI_VCAP_GetLaneNum(HI_HANDLE VcapDevHdl, const HI_MAPI_COMBO_DEV_ATTR_S* pstSensorCfg)
{
    HI_U32 u32LaneNum = 0;
    HI_U32 i;

    for (i = 0; i < HI_MAPI_SENSOR_MAX_LANE_NUM; i++) {
        if (pstSensorCfg->aLaneId[VcapDevHdl][0][i] != -1) {
            u32LaneNum ++;
        }
    }

    return u32LaneNum;
}

static HI_S32 MAPI_VCAP_SetSerdesAttr(HI_HANDLE SerdesHdl, serdes_dev_attr_t stSerdesAttr)
{
    HI_S32 s32Ret;
    HI_CHAR acDevFile[SERDES_DEV_FILE_MAX_LEN] = {0};

    s32Ret = snprintf_s(acDevFile, SERDES_DEV_FILE_MAX_LEN, SERDES_DEV_FILE_MAX_LEN, "/dev/serdes%d", SerdesHdl);
    if (s32Ret == HI_FAILURE) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP, "snprintf_s exec fail.\n");
        return HI_MAPI_SYS_ESAFEFUNC_OPERATE_FAIL;
    }

    HI_HANDLE fd = open(acDevFile, O_RDWR);
    if (fd <= 0) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP, "open serdes dev failed.\n");
        return HI_MAPI_VCAP_EOPERATE_FAIL;
    }

    s32Ret = ioctl(fd, HI_SERDES_START, &stSerdesAttr);
    if (s32Ret != HI_SUCCESS) {
        close(fd);
        fd = -1;
        MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP, "SERDES_START failed.\n");
        return HI_MAPI_VCAP_EOPERATE_FAIL;
    }

    close(fd);
    fd = -1;

    return HI_SUCCESS;
}

HI_S32 HI_MAPI_VCAP_RegSerdesModule(HI_HANDLE SerdesHdl, HI_HAL_SERDES_DEV_S *pstHalDev)
{
    HI_S32 s32Ret;
    HI_U32 u32LaneNum;
    HI_S32 i;
    HI_HANDLE SerdevBindDev;
    HI_MAPI_COMBO_DEV_ATTR_S stSensorCfg;
    serdes_dev_attr_t stSerdesAttr;
    MAPI_GLOB_DEV_ATTR_S *pstDevAtr = NULL;

    CHECK_MAPI_VCAP_HANDLE_RET("SerdesHdl", SerdesHdl, (HI_MAPI_VCAP_SERDES_MAX_NUM - 1));
    CHECK_MAPI_VCAP_NULL_PTR_RET(pstHalDev);

    if (g_stSerdesDev[SerdesHdl].bEnable == HI_TRUE) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP, "Serdes[%d] has been registered\n", SerdesHdl);
        return HI_SUCCESS;
    }

    if (pstHalDev->u32BindNum >= HI_MAPI_VCAP_SERDES_BINDDEV_MAX_NUM) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP, "Serdes[%d] bind dev num over max(%d)\n", SerdesHdl,
            HI_MAPI_VCAP_SERDES_BINDDEV_MAX_NUM);
        return HI_MAPI_VCAP_EILLEGAL_PARA;
    }

    for (i = 0; i < pstHalDev->u32BindNum; i++) {
        CHECK_MAPI_VCAP_HANDLE_RET("Serdes BindDevHdl", pstHalDev->BindDevHdl[i], (HI_MAPI_VCAP_MAX_DEV_NUM - 1));

        pstDevAtr = MAPI_VCAP_GetDevAttr(pstHalDev->BindDevHdl[i]);
        if (pstDevAtr->bSensorInit == HI_TRUE) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP,
                "Serdes vcapdev:%d,  you should reg serdes[%d] before sensor init, \n", SerdesHdl,
                pstHalDev->BindDevHdl[i]);
            return HI_MAPI_VCAP_ENOT_PERM;
        }
    }

    /* the dev bind to the same serdes use the same sensor type and dev cfg currently,
        for the dev is related to sensor in vcap struct */
    SerdevBindDev = pstHalDev->BindDevHdl[0];

    /* According to the sensor type to find which sensor is the use of the configuration file */
    s32Ret = MAPI_SENSOR_GetConfig(g_as32SerdesSnsType[SerdevBindDev], &stSensorCfg);
    CHECK_MAPI_VCAP_RET(s32Ret, "no this dev[%d] bind to serdes[%d] type:%d\n",
        SerdevBindDev, SerdesHdl, g_as32SerdesSnsType[SerdevBindDev]);

    /* judge the serdes mode */
    u32LaneNum = MAPI_VCAP_GetLaneNum(SerdevBindDev, &stSensorCfg);

    s32Ret = memset_s(&stSerdesAttr, sizeof(serdes_dev_attr_t), 0, sizeof(serdes_dev_attr_t));
    MAPI_CHECK_RET(HI_MAPI_MOD_VCAP, "memset_s", s32Ret);

    /* judge the serdes mode */
    if ((u32LaneNum == 4) && (pstHalDev->enWdrMode == WDR_MODE_NONE)) { // 4: lane num
        stSerdesAttr.serdes_mode = SERDES_MODE_4LANE_LINEAR;
    } else if ((u32LaneNum == 4) && (pstHalDev->enWdrMode != WDR_MODE_NONE)) { // 4: lane num
        stSerdesAttr.serdes_mode = SERDES_MODE_4LANE_WDR;
    } else if ((u32LaneNum == 2) && (pstHalDev->enWdrMode == WDR_MODE_NONE)) { // 2: lane num
        stSerdesAttr.serdes_mode = SERDES_MODE_2LANE_LINEAR;
    } else if ((u32LaneNum == 2) && (pstHalDev->enWdrMode != WDR_MODE_NONE)) { // 2: lane num
        stSerdesAttr.serdes_mode = SERDES_MODE_2LANE_WDR;
    } else {
        MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP, "laneNum(%d) WdrMode(%d) is not support.\n", u32LaneNum,
            pstHalDev->enWdrMode);
        return HI_MAPI_VCAP_ENOTSUPPORT;
    }

    stSerdesAttr.devno = (unsigned char)SerdesHdl;
    stSerdesAttr.sendes_en = HI_TRUE;
    stSerdesAttr.sensor_i2c_addr = stSensorCfg.sensor_i2c_addr;

    s32Ret = MAPI_VCAP_SetSerdesAttr(SerdesHdl, stSerdesAttr);
    CHECK_MAPI_VCAP_RET(s32Ret, "Set Serdes[%d] Attr fail.\n", SerdesHdl);

    for (i = 0; i < pstHalDev->u32BindNum; i++) {
        g_stSerdesDev[SerdesHdl].BindDevHdl[i] = pstHalDev->BindDevHdl[i];
    }

    g_stSerdesDev[SerdesHdl].u32BindNum = pstHalDev->u32BindNum;
    g_stSerdesDev[SerdesHdl].stSerdesAttr.devno = stSerdesAttr.devno;
    g_stSerdesDev[SerdesHdl].stSerdesAttr.sensor_i2c_addr = stSensorCfg.sensor_i2c_addr;
    g_stSerdesDev[SerdesHdl].stSerdesAttr.serdes_mode = stSerdesAttr.serdes_mode;
    g_stSerdesDev[SerdesHdl].bEnable = HI_TRUE;
    g_stSerdesDev[SerdesHdl].multiInput = pstHalDev->multiInput;

    return HI_SUCCESS;
}

HI_S32 HI_MAPI_VCAP_UnRegSerdesModule(HI_HANDLE SerdesHdl)
{
    HI_S32 s32Ret;
    HI_S32 u32BindNum;
    HI_S32 i;
    serdes_dev_attr_t stSerdesAttr;
    MAPI_GLOB_DEV_ATTR_S *pstDevAtr = NULL;

    CHECK_MAPI_VCAP_HANDLE_RET("SerdesHdl", SerdesHdl, (HI_MAPI_VCAP_SERDES_MAX_NUM - 1));
    if (g_stSerdesDev[SerdesHdl].bEnable == HI_FALSE) {
        MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP, "Serdes[%d] has not been registered\n", SerdesHdl);
        return HI_SUCCESS;
    }

    u32BindNum = g_stSerdesDev[SerdesHdl].u32BindNum;
    for (i = 0; i < u32BindNum; i++) {
        pstDevAtr = MAPI_VCAP_GetDevAttr(g_stSerdesDev[SerdesHdl].BindDevHdl[i]);
        if (pstDevAtr->bSensorInit == HI_TRUE) {
            MAPI_ERR_TRACE(HI_MAPI_MOD_VCAP,
                "Serdes vcapdev:%d,  you should unreg serdes[%d] after sensor deinit.\n",
                g_stSerdesDev[SerdesHdl].BindDevHdl[i], SerdesHdl);
            return HI_MAPI_VCAP_ENOT_PERM;
        }
    }

    s32Ret = memset_s(&stSerdesAttr, sizeof(serdes_dev_attr_t), 0, sizeof(serdes_dev_attr_t));
    MAPI_CHECK_RET(HI_MAPI_MOD_VCAP, "memset_s", s32Ret);

    stSerdesAttr.devno = SerdesHdl;
    stSerdesAttr.sensor_i2c_addr = g_stSerdesDev[SerdesHdl].stSerdesAttr.sensor_i2c_addr;
    stSerdesAttr.serdes_mode = g_stSerdesDev[SerdesHdl].stSerdesAttr.serdes_mode;
    stSerdesAttr.sendes_en = HI_FALSE;

    s32Ret = MAPI_VCAP_SetSerdesAttr(SerdesHdl, stSerdesAttr);
    CHECK_MAPI_VCAP_RET(s32Ret, "Set Serdes[%d] Attr fail.\n", SerdesHdl);

    g_stSerdesDev[SerdesHdl].bEnable = HI_FALSE;
    s32Ret = MAPI_VCAP_ResetSerdesDev(SerdesHdl);
    CHECK_MAPI_VCAP_RET(s32Ret, "reset Serdes[%d] Attr fail.\n", SerdesHdl);

    return HI_SUCCESS;
}
#endif

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
